//
// Created by Tony on 2024/5/29.
//

#ifndef RT_DATA_FRAME_H
#define RT_DATA_FRAME_H

#include "../Slot.h"
#include "../rt_code/Method.h"
#include "Object.h"
#include "Stack.h"
#include <cstdint>

namespace RtData {

class Frame {
    vector<Runtime::Slot> mSlots;
    uint16_t mTop{0};
    uint32_t mPC{0};
    shared_ptr<RtCode::Method> mMethod;
    shared_ptr<Frame> mLower;
    shared_ptr<Stack> mStack;

public:
    Frame(const shared_ptr<Stack>& stack, const shared_ptr<RtCode::Method>& method)
        : mStack(stack), mMethod(method), mSlots(method->getMaxStack()),
          mTop(method->getLocalSlotCount()) {}

    void setMethod(const shared_ptr<RtCode::Method>& method) { // TODO delete
        mMethod = method;
        mTop = method->getLocalSlotCount();
    }

    shared_ptr<RtCode::Method>& getMethod() { return mMethod; }
    uint16_t getTop() const { return mTop; }
    shared_ptr<Stack> getStack() { return mStack; }

    uint32_t getNextPC() const { return mPC; }
    void setNextPC(uint32_t pc) { mPC = pc; }
    void revertNextPC() { mPC = mStack->getPC(); }

    void setLower(const shared_ptr<Frame>& frame) { mLower = frame; }
    shared_ptr<Frame> getLower() { return mLower; }

    int64_t getInt64(uint16_t slotId) const { return mSlots[slotId].getInt64(); }

    void pushRef(Object* ref) { mSlots[mTop++].setRef(ref); }
    Object* popRef() { return mSlots[--mTop].getRef(); }
    Object* getRefFromTop(uint16_t offset) { return mSlots[mTop - 1 - offset].getRef(); }

    void pushValue(Runtime::RtTaggedValue value) { mSlots[mTop++].setValue(value); }
    Runtime::RtTaggedValue popValue() { return mSlots[--mTop].getValue(); }

    Runtime::Slot popSlot() { return mSlots[--mTop]; }
    void pushSlot(const Runtime::Slot& slot) { mSlots[mTop++] = slot; }
    void setSlot(uint16_t slotId, const Runtime::Slot& slot) { mSlots[slotId] = slot; }
    Runtime::Slot getSlot(uint16_t slotId) const { return mSlots[slotId]; }
};

} // namespace RtData

#endif // RT_DATA_FRAME_H
